﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RPN
{
    /// <summary>
    /// реализация ПОЛИЗ
    /// </summary>
    class RevPNotation
    {
        /* Приоритеты операций
         *  * /  - 1
         *  + -  - 0
         */
        private Stack<char> _stack; // стековая машина для вычислений
        public string InputString;
        public string OutputString; // выходная страка с постфиксной записью выражения
        private int _ErrorCode;     // если выражение задано не верно
        private string[] _Operations = { "+", "-","*","/","(",")"};
        private int[] _Priority = { 0,0,1,1 };
       private char[] charSeparators = new char[] { ' ' };
       public  RevPNotation()
        {
            this._stack = new Stack<char>();
            this.OutputString = "";
            this.InputString = "";
            this._ErrorCode = 0;
        }

        /// <summary>
        /// построение постфиксной записи
        /// </summary>
        void ToReversePolishNotation()
        {
            
            string[] str = InputString.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
            for (int i=0; i<str.Length;i++)
            {
                double temp = 0;
                //если число, то в выходную строку
                bool isDouble = Double.TryParse(str[i], out temp);
                if (isDouble)
                {
                    OutputString += str[i] + " ";
                }
                // если функция или скобки то в стек
                else
                {
                    // если встретили ")" то выталкиваем все из стек пока на верхушке не будет "("
                        if (str[i].Equals(")"))
                        {
                            

                            while (true)
                            {
                                if (this._stack.Peek().Equals('('))
                                {
                                    this._stack.Pop();
                                    break;
                                }
                                
                                OutputString += this._stack.Pop().ToString()+" ";
                            }

                        }
                    
                    for (int j=0; j<this._Operations.Length;j++)
                    {
                        
                        if (str[i].Equals(this._Operations[j]))
                        {
                            if (!str[i].Equals("("))
                            {
                                if (!str[i].Equals(")"))
                                {
                                    if (this._stack.Count > 0)
                                    {
                                        if (!this._stack.Peek().Equals('('))
                                        {
                                            if (!this._stack.Peek().Equals(')'))
                                            {

                                                if (_Priority[GetElementIndex(Convert.ToString(str[i]), this._Operations)] <= _Priority[GetElementIndex(Convert.ToString(this._stack.Peek()), this._Operations)])
                                                {
                                                    OutputString += this._stack.Pop().ToString()+ " ";
                                                }
                                            }
                                        }
                                    }


                                }
                            }
                           
                                this._stack.Push(Convert.ToChar(str[i]));
                                break;
                            
                        }

                    }
                }

            }

            foreach (char item in this._stack)
            {
                OutputString += item+" ";
            }
            // Магическая строка, которая заставляет код работать правильно,
            // убирает из выходной строки скобки, которые туда попадают, магическим образом

            OutputString = OutputString.Replace(")", "");
        }

        int GetElementIndex(string whatFind, string[] WhereFind)
        {
            int Result = 0;
            for (int i = 0; i < WhereFind.Length; i++)
            {
                if (whatFind.Equals(WhereFind[i]))
                {
                    Result = i;
                    break; 
                    
                }
                
            }

            return Result; 
        }
        public void Clear()
        {
            this._stack = new Stack<char>(); 
            this.OutputString = "";
            this.InputString = "";
            this._ErrorCode = 0;
        }
        /// <summary>
        /// вычисление выражения в постфиксной форме
        /// </summary>
        /// <returns>Результат вычисления</returns>
     public   string Calculate()
        {
            int res = 0;
            int A = 0;
            int B = 0;
            ToReversePolishNotation();
          Stack<string>  Numstack = new Stack<string>();
         // пока !EOS
         // пока не встретим функцию записываем число в стек
         // как встретили функцию берем из стека два верхних числа и вычисляем
         // результат кладем в стек

           int a=0;
        string[] line = OutputString.Split(charSeparators,StringSplitOptions.RemoveEmptyEntries);
                foreach (string item in line)
	            {
		 

	            if (int.TryParse(item, out  a))
                {
                    Numstack.Push(a.ToString());
                }
                else
                {
                    switch (Convert.ToChar(item))
                    {
                        case '+' :
                             A = int.Parse(Numstack.Pop().ToString());
                             B = int.Parse(Numstack.Pop().ToString());
                             res = A + B;
                            break;
                        case '-':
                             A = int.Parse(Numstack.Pop().ToString());
                             B = int.Parse(Numstack.Pop().ToString());
                             res = A - B;
                            break;
                        case '*':
                             A = int.Parse(Numstack.Pop().ToString());
                             B = int.Parse(Numstack.Pop().ToString());
                             res = A * B;
                            break;
                        case '/':
                             A = int.Parse(Numstack.Pop().ToString());
                             B = int.Parse(Numstack.Pop().ToString());
                            res = A  / B;
                            break;

                    }
                    Numstack.Push(res.ToString());
                }
                }
            
            return Numstack.Pop().ToString();
        }
    }
}
